﻿using System;
using System.Collections.Generic;
using System.Linq;
using CSharpConsoleTestSolution.Bean;

namespace CSharpConsoleTestSolution.Demo {
    
    /**
     * 1.传值参数
     * 2.引用参数
     * 3.输出参数
     * 4.数组参数
     * 5.具名参数
     * 6.可选参数
     * 7.扩展方法(this参数)
     * 8.LinQ 方法
     */
    public class P18_Params {
        
        /**
         * 1.传值参数, 时间: 05:10
         */
        public static void value_params() {
            Console.WriteLine("1.传值参数");
            Console.WriteLine("public void AddOne(int x) {}");
            
            var person = new Person("张三") {
                Score = 66
            };
            Console.WriteLine($"person.Score={person.Score}");
            Method1(person);
            Console.WriteLine($"person.Score={person.Score}");
        }

        /**
         * 2.引用参数, 时间: 21:15
         * ref 修饰的参数(可为null), 不会对传入的参数创建副本!
         */
        public static void ref_params() {
            Console.WriteLine("\n");
            Console.WriteLine("2.引用参数: ref 修饰的参数(可为null), 不会对传入的参数创建副本!");
            int x = 5;
            Method2(ref x);
            Console.WriteLine("int x = 5;");
            Console.WriteLine("Method2(ref x);");
            Console.WriteLine($"x = {x}");

            Person person = null;
            Console.WriteLine("person=null");
            Method3(ref person);
            Console.WriteLine($"person.Score={person.Score}");
        }

        /**
         * 3.输出参数, 时间: 36:15
         * out 修饰的参数(可为null), 是输出形参, 类似于引用形参, 输出形参不创建新的存储位置.
         */
        public static void out_params() {
            Console.WriteLine("\n");
            Console.WriteLine("3.输出参数: out 修饰的参数(可为null), 是输出形参, 类似于引用形参, 输出形参不创建新的存储位置.");
            string strX = "3.1415926927";
            string strY = "3.1415926927a";
            double xDouble = 0.11;
            double yDouble = 0.11;
            Console.WriteLine($"string strX = {strX}, strY = {strY}, xDouble = {xDouble}, yDouble = {yDouble}");

            var resultX = double.TryParse(strX, out xDouble);
            var resultY = double.TryParse(strY, out yDouble);
            Console.WriteLine("var result = double.TryParse(strX, out xDouble);");
            Console.WriteLine($"TryParse: resultX = {resultX}, resultY = {resultY}, xDouble = {xDouble}, yDouble = {yDouble}");

            Console.WriteLine("\n自定义 TryParse:");
            resultX = DoubleParser.TryParse(strX, out xDouble);
            resultY = DoubleParser.TryParse(strY, out yDouble);
            Console.WriteLine("resultX = DoubleParser.tryParse(strX, out xDouble);");
            Console.WriteLine($"TryParse: resultX = {resultX}, resultY = {resultY}, xDouble = {xDouble}, yDouble = {yDouble}");
        }

        /**
         * 4.数组参数, 时间: 54:25
         * params 修饰的数组参数(params object[] args), 参数个数可变
         */
        public static void params_params() {
            Console.WriteLine("\n");
            Console.WriteLine("4.数组参数: params 修饰的数组参数(params object[] args), 参数个数可变");

            //1.Console.WriteLine
            Console.WriteLine("Console.WriteLine: I'm {0}, age is {1}, living in {2}, work is {3}", 
                "Tim", 23, "重庆", "Programmer!"
                );
            
            //2.String.Format
            var format = String.Format("String.Format: {0}, {1},  {2},  {3}", 123, 345, 567, 789);
            Console.WriteLine(format);
            
            //3.String.Split
            var str = "12_3_45 _78";
            var splits = str.Split('_', ' ');
            Console.Write("String.Split: ");
            foreach (var split in splits) {
                Console.Write(split + "   ");
            }
            Console.WriteLine();

            var sum = CalculateSum();
            Console.WriteLine($"自定义数组参数求和: sum= {sum}");
        }

        /**
         * 5.具名参数(参数的位置不再受约束), 时间: 1:01:14
         * Method4(age: 213, name: "张三");
         */
        public static void name_params() {
            Console.WriteLine("\n");
            Console.WriteLine("5.具名参数(参数的位置不再受约束)");
            Console.WriteLine("Method4(age: 213, name: \"张三\");");
            Method4(age: 213, name: "张三");
        }

        /**
         * 6.可选参数(参数有默认值, ∴可选), 时间: 1:04:22
         * Method5(string name, int age = 23)
         */
        public static void optional_params() {
            Console.WriteLine("\n");
            Console.WriteLine("6.可选参数(参数有默认值, ∴可选)");
            Console.WriteLine("Method5(string name, int age, int height = 175)");
            Console.WriteLine("Method5(string name, int age = 23, int height = 175)");
            Console.WriteLine("Method5(string name = \"李四\", int age, int height = 175) //报错: 有默认值的要放到后面部分, 否则编译报错!");
            Method5(name: "张三");
        }

        /**
         * 7.扩展方法(this参数), 时间: 1:05:45
         * 方法必须是 public static
         * 必须是形参列表中的第1个, 由 this 修饰
         * 必须由1个静态类(一般类名为 SomeTypeExtension) 来统一收纳对 SomeType 类型的扩展方法
         * 举例: LinQ 方法 (Language Integrated Query, 语言集成查询, 发音"link")
         */
        public static void this_params_extension_method() {
            Console.WriteLine("\n");
            Console.WriteLine("7.扩展方法(this参数)");

            double pi = 3.1415926;
            double round = Math.Round(pi, 5);
            Console.WriteLine($"Math.Round(pi, 5) = {round}");
            
            Console.WriteLine("[public] static class DoubleExtension {");
            Console.WriteLine("    public static double Round(this double value, int digits) {");
            Console.WriteLine("        return Math.Round(value, digits);");
            Console.WriteLine("    }");
            Console.WriteLine("}");

            var round6 = pi.Round(6);
            Console.WriteLine($"pi.Round(6) = {round6}");
        }

        /**
         * 8.LinQ 方法, 时间: 1:11:25
         * Language Integrated Query, 语言集成查询, 发音"link"
         */
        public static void linq_params() {
            Console.WriteLine("\n");
            Console.WriteLine("8.LinQ 方法");
            List<int> list0 = new List<int>() { 11, 20, 30, 43, 52 };
            List<int> list1 = new List<int>() { 1, 2, 30, 43, 52 };
            var isAllGreaterThan10_0 = AllGreaterThan_10(list0);
            var isAllGreaterThan10_1 = AllGreaterThan_10(list1);
            Console.WriteLine($"isAllGreaterThan10_0: {isAllGreaterThan10_0}");
            Console.WriteLine($"isAllGreaterThan10_1: {isAllGreaterThan10_1}");
            
            Console.WriteLine("using System.Linq;");
            Console.WriteLine("var isAllGreaterThan10_0 = list0.All(i => i > 10);");
            Console.WriteLine("var isAllGreaterThan10_1 = list1.All(i => {");
            Console.WriteLine("    var greater = i > 10;");
            Console.WriteLine("    return greater;");
            Console.WriteLine("});");

            isAllGreaterThan10_0 = list0.All(i => i > 10);
            isAllGreaterThan10_1 = list1.All(i => {
                var greater = i > 10;
                return greater;
            });
            Console.WriteLine($"isAllGreaterThan10_0: {isAllGreaterThan10_0}");
            Console.WriteLine($"isAllGreaterThan10_1: {isAllGreaterThan10_1}");
        }
        


        public static void Method1(Person person) {
            person.Score = 99;
        }
        
        public static void Method2(ref int x) {
            x = 99;
            x += 1;
        }
        public static void Method3(ref Person person) {
            if (person == null) person = new Person("Tim");
            person.Score = 99;
        }
        
        private static int CalculateSum(params int[] args) {
            if (args == null || args.Length == 0) return 0;
            var sum = 0;
            foreach (var i in args) sum += i;
            return sum;
        }
        
        public static void Method4(string name, int age) {
            Console.WriteLine($"name = {name}, age = {age}");
        }

        public static void Method5(string name, int age = 23, int height = 175) {
            Console.WriteLine($"name = {name}, age = {age}, height = {height}cm");
        }

        public static bool AllGreaterThan_10(List<int> numbers) {
            foreach (var number in numbers) {
                if (number <= 10) return false;
            }
            return true;
        }

        private class DoubleParser {

            public static bool TryParse(string s, out double result) {
                //报错: Out parameter 'result' might not be initialized before accessing
                // var result2 = result;
                try {
                    result = double.Parse(s);
                    return true;
                } catch (Exception e) {
                    // Console.WriteLine(e);
                    result = 0;     //double.TryParse 解析错误后就是返回的 0 ...
                    return false;
                }
            }
        }
    }

    //private 报错, 为啥?
    /*private*/ static class DoubleExtension {
        /// <summary>
        /// 精确到小数点后几位, 四舍五入
        /// </summary>
        /// <param name="value">double值</param>
        /// <param name="digits">精确到小数点后第几位</param>
        /// <returns></returns>
        public static double Round(this double value, int digits) {
            return Math.Round(value, digits);
        }
    }
}